<template>
  <view :class="loadingClass">
    <!-- 旋转加载器 -->
    <view v-if="type === 'spinner'" class="loading-spinner">
      <view class="spinner-circle"></view>
    </view>

    <!-- 点状加载器 -->
    <view v-else-if="type === 'dots'" class="loading-dots">
      <view class="dot" v-for="(_, index) in 3" :key="index"></view>
    </view>

    <!-- 脉冲加载器 -->
    <view v-else-if="type === 'pulse'" class="loading-pulse">
      <view class="pulse-circle"></view>
    </view>

    <!-- 条形加载器 -->
    <view v-else-if="type === 'bars'" class="loading-bars">
      <view class="bar" v-for="(_, index) in 4" :key="index"></view>
    </view>

    <!-- 自定义加载器 -->
    <slot v-else></slot>

    <!-- 加载文字 -->
    <text v-if="text" :class="textClass">{{ text }}</text>
  </view>
</template>

<script setup lang="ts">
import { computed } from 'vue'

interface Props {
  // 加载器类型
  type?: 'spinner' | 'dots' | 'pulse' | 'bars' | 'custom'
  // 加载文字
  text?: string
  // 尺寸
  size?: number | 'small' | 'medium' | 'large'
  // 颜色
  color?: string
  // 是否遮罩
  overlay?: boolean
  // 是否全屏
  fullscreen?: boolean
  // 背景透明度
  backgroundOpacity?: number
  // 自定义类名
  customClass?: string
}

const props = withDefaults(defineProps<Props>(), {
  type: 'spinner',
  text: '',
  size: 'medium',
  color: '',
  overlay: false,
  fullscreen: false,
  backgroundOpacity: 0.8,
  customClass: '',
})

// 尺寸映射
const sizeMap = {
  small: 24,
  medium: 32,
  large: 48,
}

// 计算尺寸
const sizeValue = computed(() => {
  if (typeof props.size === 'number') {
    return props.size
  }
  return sizeMap[props.size]
})

// 加载器样式
const loadingClass = computed(() => {
  const baseClass = 'flex items-center justify-center'

  const sizeClass = typeof props.size === 'number' ? '' : `loading-${props.size}`

  const overlayClass = props.overlay ? 'fixed inset-0 z-50' : ''

  const fullscreenClass = props.fullscreen ? 'fixed inset-0 z-50' : ''

  const backgroundClass = (props.overlay || props.fullscreen)
    ? 'bg-black bg-opacity-80'
    : ''

  const directionClass = props.text ? 'flex-col' : ''

  return [
    baseClass,
    sizeClass,
    overlayClass,
    fullscreenClass,
    backgroundClass,
    directionClass,
    props.customClass,
  ].filter(Boolean).join(' ')
})

// 文字样式
const textClass = computed(() => {
  const sizeClasses = {
    small: 'text-sm',
    medium: 'text-base',
    large: 'text-lg',
  }

  return [
    'mt-sm text-text-secondary',
    typeof props.size === 'number' ? '' : sizeClasses[props.size],
  ].filter(Boolean).join(' ')
})

// 计算加载器样式
const loaderStyle = computed(() => {
  const size = typeof props.size === 'number' ? `${sizeValue.value}rpx` : ''
  const color = props.color || 'var(--novel-primary)'

  return {
    width: size,
    height: size,
    borderTopColor: color,
    borderLeftColor: color,
    backgroundColor: color,
  }
})
</script>

<style scoped>
.loading-small {
  --loader-size: 24rpx;
}

.loading-medium {
  --loader-size: 32rpx;
}

.loading-large {
  --loader-size: 48rpx;
}

/* 旋转加载器 */
.loading-spinner {
  display: flex;
  align-items: center;
  justify-content: center;
}

.spinner-circle {
  width: var(--loader-size, 32rpx);
  height: var(--loader-size, 32rpx);
  border: 2rpx solid transparent;
  border-top: 2rpx solid var(--novel-primary);
  border-left: 2rpx solid var(--novel-primary);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

/* 点状加载器 */
.loading-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
}

.dot {
  width: 8rpx;
  height: 8rpx;
  background-color: var(--novel-primary);
  border-radius: 50%;
  animation: dot-bounce 1.4s ease-in-out infinite both;
}

.dot:nth-child(1) {
  animation-delay: -0.32s;
}

.dot:nth-child(2) {
  animation-delay: -0.16s;
}

/* 脉冲加载器 */
.loading-pulse {
  display: flex;
  align-items: center;
  justify-content: center;
}

.pulse-circle {
  width: var(--loader-size, 32rpx);
  height: var(--loader-size, 32rpx);
  background-color: var(--novel-primary);
  border-radius: 50%;
  animation: pulse 1.5s ease-in-out infinite;
}

/* 条形加载器 */
.loading-bars {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4rpx;
}

.bar {
  width: 4rpx;
  height: var(--loader-size, 32rpx);
  background-color: var(--novel-primary);
  border-radius: 2rpx;
  animation: bar-stretch 1.2s ease-in-out infinite;
}

.bar:nth-child(1) {
  animation-delay: -1.1s;
}

.bar:nth-child(2) {
  animation-delay: -1.0s;
}

.bar:nth-child(3) {
  animation-delay: -0.9s;
}

.bar:nth-child(4) {
  animation-delay: -0.8s;
}

/* 动画 */
@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

@keyframes dot-bounce {
  0%, 80%, 100% {
    transform: scale(0);
  }
  40% {
    transform: scale(1);
  }
}

@keyframes pulse {
  0% {
    transform: scale(0);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}

@keyframes bar-stretch {
  0%, 40%, 100% {
    transform: scaleY(0.4);
  }
  20% {
    transform: scaleY(1);
  }
}
</style>